home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / Communications Toolbox / CTB Sample Code 1.0b16 / CTB Sources / Sources 1 / Surfer.p < prev    next >
Encoding:
Text File  |  1989-10-08  |  40.2 KB  |  1,601 lines  |  [TEXT/MPS ]

  1. {------------------------------------------------------------------------------
  2. #
  3. #    Apple Products Presents
  4. #
  5. #    S U R F E R    ----- A CommToolbox Sample Application
  6. #        by Alex Kazim
  7. #
  8. #    Based on the MacDTS Simple Sample Application
  9. #
  10. #    Surfer.p    -    Pascal Source
  11. #
  12. #    Copyright © 1988-9 Apple Computer, Inc.
  13. #    All rights reserved.
  14. #
  15. #    Versions:    Sample 1.0                    08/88
  16. #                Sample 1.01                    11/88
  17. #
  18. #                Surfer 1.0                    10/89
  19. ------------------------------------------------------------------------------}
  20.  
  21. {
  22. MODIFICATION HISTORY
  23.  
  24.     9/26/89        kaz        • changed case on constants to match documentation
  25.                         • Fixed error handling to only call xxEvent() if the
  26.                         target of the event is a tool window
  27.                         • Initializes gBuffer according to sizes[cmDataIn]
  28.                         after the CMNew call
  29.                         
  30.     10/1/89        kaz        • TermGetConnEnvirons() and FTGetConnEnvirons() were
  31.                         merged into one routine: ToolGetConnEnvirons()
  32.                         • IsAppWindow() uses GetWRefCon instead of looking
  33.                         at the windowrecord refcon field.
  34.                         • Moved DiposePtr(gBuffer) to CloseWindow
  35.                         • HLock/HUnlock all the tool handles
  36.                         • Took out alerts to let the tools handle it themselves
  37.                         
  38.     10/4/89        kaz        • Was forgetting to clear gStartFT after a receive
  39.     
  40. }
  41.  
  42. PROGRAM Sample;
  43.  
  44. USES
  45.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,
  46.     CTBUtils, FTIntf,CMIntf,TMIntf, CRMIntf;
  47.  
  48. CONST
  49.     _WaitNextEvent                = $A860;
  50.     _UnimplementedToolTrap        = $A89F;
  51.     _CommToolboxTrap            = $8B;
  52.     _UnimplementedOSTrap        = $9F;
  53.  
  54.     kSysEnvironsVersion        = 1;
  55.  
  56.     kOSEvent                = app4Evt;    { event used by MultiFinder    }
  57.     kSuspendResumeMessage    = 1;        { high byte of suspend/resume event message}
  58.     kResumeMask                = 1;        { bit of message field for resume vs. suspend}
  59.      
  60.     kMinHeap    = 150 * 1024; 
  61.     kMinSpace    = 10 * 1024;
  62.     kBufferSize    = 1 * 1024;                { Data Storage Size = 1K    }
  63.     
  64.     kExtremeNeg    = -32768;
  65.     kExtremePos    = 32767 - 1;            { required for old region bug    }
  66.     
  67.     kDefaultTermTool    = 'VT102';        { what tools we want first        }
  68.     kDefaultFTTool        = 'Text';
  69.     kDefaultConnTool    = 'Serial';
  70.     
  71.     rMenuBar    = 128;                    { application's menu bar    }
  72.     rAboutAlert    = 128;                    { about alert                }
  73.     rUserAlert    = 129;                    { error user alert            }
  74.     rWindow        = 128;                    { application's window        }
  75.  
  76.     mApple            = 128;                    {Apple menu}
  77.     iAbout            = 1;
  78.  
  79.     mFile            = 129;                    {File menu}
  80.     iNew            = 1;
  81.     iOpen            = 2;
  82.     iClose            = 4;
  83.     iSendFile        = 9;
  84.     iReceiveFile    = 10;
  85.     iQuit            = 15;
  86.  
  87.     mEdit            = 130;                    {Edit menu}
  88.     iUndo            = 1;
  89.     iCut            = 3;
  90.     iCopy            = 4;
  91.     iPaste            = 5;
  92.     iClear            = 6;
  93.  
  94.     mSettings        = 131;                    {Settings menu}
  95.     iConnection        = 1;
  96.     iFileTransfer    = 2;
  97.     iTerminal        = 3;
  98.     
  99.     kDITop        = $0050;
  100.     kDILeft        = $0070;
  101.  
  102.  
  103. VAR
  104.     gHasWaitNextEvent    : BOOLEAN;        {set up by Initialize}
  105.     gInBackground        : BOOLEAN;        {maintained by Initialize and DoEvent    }
  106.  
  107.     gStopped            : BOOLEAN;        {maintained by Initialize and SetLight    }
  108.     
  109.     gTerm                : TermHandle;    { Tool Handles: Single Session            }
  110.     gConn                : ConnHandle;
  111.     gFT                    : FTHandle;
  112.  
  113.     gBuffer                : Ptr;            { Data Storage for Reads/Writes            }
  114.     
  115.     gFTSearchRefNum        : LONGINT;        { Auto-Initiate File Transfers            }
  116.     gStartFT            : BOOLEAN;        { Auto-start                            }
  117.     gWasFT                : BOOLEAN;        { In progress                            }
  118.         
  119. PROCEDURE AlertUser(msg: Str255; fatal: BOOLEAN); FORWARD;
  120. PROCEDURE Terminate; FORWARD;
  121.  
  122. { ******************************************************************
  123. *    TrapAvailable    - Checks to see if a given trap is implemented
  124. *
  125. *        tNumber        - trap number
  126. *        tType        - type of trap
  127. *
  128. *        returns        - true if it exists
  129. *
  130. ********************************************************************* }
  131. {$S Initialize}
  132. FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
  133. VAR
  134.     unImplemented    : INTEGER;
  135.     
  136. BEGIN
  137.     IF tType = OSTrap THEN
  138.         unImplemented := _UnimplementedOSTrap
  139.     ELSE
  140.         unImplemented := _UnimplementedToolTrap;
  141.  
  142.     TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(unImplemented);
  143. END; {TrapAvailable}
  144.  
  145.  
  146. { ******************************************************************
  147. *    TermSendProc    - Sends the data out the connection
  148. *
  149. *        thePtr        - the data to send
  150. *        theSize        - bytes to send
  151. *        refcon        - terminal tool refcon
  152. *        flags        - connection flags
  153. *
  154. *        returns        - bytes sent
  155. *
  156. ********************************************************************* }
  157. {$S Main}
  158. FUNCTION TermSendProc(thePtr: Ptr;theSize: LONGINT;
  159.                     refcon: LONGINT;flags: INTEGER): LONGINT;
  160. VAR
  161.     theErr        : CMErr;
  162.     
  163. BEGIN
  164.     TermSendProc := 0;                        { Assume the worst            }
  165.     
  166.     IF gConn <> NIL THEN BEGIN    
  167.     
  168.         { DO NOT check to see if the conn is first open before sending    }
  169.         { as the tool might be directly interpreting the data            }
  170.  
  171.         theErr := CMWrite(gConn,thePtr,theSize,
  172.                             cmData,FALSE,NIL,0,flags);
  173.                             
  174.         IF (theErr = noErr) THEN
  175.             TermSendProc := theSize;        { If ok, we sent all        }
  176.         
  177.     END; { Good Connection    }
  178.     
  179. END; { TermSendProc        }
  180.  
  181.  
  182.  
  183. { ******************************************************************
  184. *    TermRecvProc    - Gets the data from the connection and sends 
  185. *                    it to the terminal tool.
  186. *
  187. *        NOTE        - This is NOT a callback proc, but does 
  188. *                    resemble the functionality.
  189. *
  190. *
  191. ********************************************************************* }
  192. {$S Main}
  193. PROCEDURE TermRecvProc;
  194. VAR
  195.     theErr        : CMErr;        { Any errors            }
  196.     status        : CMStatFlags;    { For the conn tool        }
  197.     sizes        : CMBufferSizes;
  198.     flags        : INTEGER;
  199.     
  200. BEGIN
  201.     IF (gConn <> NIL) AND (gTerm <> NIL) THEN BEGIN
  202.     
  203.         { Get the state of the connection    }
  204.         theErr := CMStatus(gConn, sizes, status);
  205.         
  206.         IF (theErr = noErr) THEN  BEGIN
  207.         
  208.             { Route the data if we have any            }
  209.             IF (BAND(status, cmStatusOpen + cmStatusDataAvail) <> 0) AND 
  210.                                     (sizes[cmDataIn] <> 0) THEN BEGIN
  211.                 
  212.                 { Don't overflow my buffer        }
  213.                 IF sizes[cmDataIn] > kBufferSize THEN
  214.                     sizes[cmDataIn] := kBufferSize;
  215.             
  216.                 { Tell the tool to get the data    }
  217.                 theErr := CMRead(gConn, gBuffer, sizes[cmDataIn],
  218.                                         cmData, FALSE,NIL,0,flags);
  219.                 
  220.                 { Send data to the terminal    }
  221.                 IF (theErr = noErr) THEN
  222.                     sizes[cmDataIn] := TMStream(gTerm,gBuffer,
  223.                                             sizes[cmDataIn],flags);
  224.                                             
  225.             END; { sizes <> 0    }
  226.                 
  227.         END; { Good Status        }
  228.         
  229.         IF (theErr <> noErr) THEN
  230.             ;        { Connection tool will alert the user on an error    }
  231.         
  232.     END; { Good term & conn    }
  233.     
  234. END; { TermRecvProc        }
  235.  
  236.  
  237.  
  238. { ******************************************************************
  239. *    ToolGetConnEnvirons    - Gets the connection environs for
  240. *                        the FT or Term tool
  241. *
  242. *        refCon            - the tool refcon
  243. *        theEnvirons        - the environment
  244. *
  245. *        returns            - an environment error
  246. *
  247. ********************************************************************* }
  248. {$S Main}
  249. FUNCTION ToolGetConnEnvirons(refCon: LONGINT;
  250.                         VAR theEnvirons: ConnEnvironRec): OSErr;
  251. BEGIN
  252.     ToolGetConnEnvirons := envNotPresent;        { pessimism         }
  253.     
  254.     { Version is set by the tool    }
  255.     IF (gConn <> NIL) THEN
  256.         ToolGetConnEnvirons := CMGetConnEnvirons(gConn,theEnvirons);
  257.     
  258. END; { TermGetConnEnvirons    }
  259.  
  260.  
  261.  
  262. { ******************************************************************
  263. *    FTSendProc    - Sends data during a file transfer
  264. *
  265. *        thePtr        - data to send
  266. *        theSize        - bytes to send
  267. *        refcon        - the FTtool refcon
  268. *        channel        - which channel to use
  269. *        flags        - connection flags
  270. *
  271. *        returns        - bytes sent
  272. *
  273. ********************************************************************* }
  274. {$S Main}
  275. FUNCTION FTSendProc(thePtr: Ptr;theSize: LONGINT;refcon: LONGINT;
  276.                         channel: CMChannel;flags: INTEGER) : LONGINT;
  277. VAR
  278.     theErr : CMErr;
  279.     
  280. BEGIN
  281.     FTSendProc := 0;                    { Assume the worst        }
  282.     
  283.     IF gConn <> NIL THEN BEGIN
  284.                                         { Send the data            }
  285.         theErr := CMWrite(gConn,thePtr,theSize,channel, 
  286.                                         FALSE, NIL, 0, flags);
  287.         IF (theErr = noErr) THEN
  288.             FTSendProc := theSize;        { if ok, we sent all    }
  289.  
  290.     END; { Good Connection    }
  291.     
  292. END; { FTSendProc    }
  293.  
  294.  
  295.  
  296. { ******************************************************************
  297. *    FTReceiveProc    - Gets data during a file transfer
  298. *
  299. *        thePtr        - place for data
  300. *        theSize        - bytes to get
  301. *        refcon        - the FTtool refcon
  302. *        channel        - which channel to use
  303. *        flags        - connection flags
  304. *
  305. *        returns        - bytes gotten
  306. *
  307. ********************************************************************* }
  308. {$S Main}
  309. FUNCTION FTReceiveProc(thePtr: Ptr;theSize: LONGINT;refcon: LONGINT; 
  310.                                 channel: CMChannel;VAR flags: INTEGER): LONGINT;
  311. VAR
  312.     theErr : CMErr;
  313.     
  314. BEGIN
  315.     FTReceiveProc := 0;                    { Assume the worst        }
  316.     
  317.     IF gConn <> NIL THEN BEGIN
  318.                                         { Read all the data        }
  319.         theErr := CMRead(gConn,thePtr,theSize, 
  320.                                         channel,FALSE,NIL,0,flags);
  321.         IF (theErr = noErr) THEN
  322.             FTReceiveProc := theSize;    { if ok, we got all        }
  323.  
  324.     END; { Good Connection    }
  325.     
  326. END; { FTReceiveProc    }
  327.  
  328.  
  329. { ******************************************************************
  330. *    AutoRecCallback    - Sets the file transfer flag if a auto-
  331. *                    receive string was found.
  332. *
  333. *        theConn            - which connection tool found it
  334. *        data            - ptr to last character in the match
  335. *        refNum            - which search was found
  336. *
  337. ********************************************************************* }
  338. {$S Main}
  339. PROCEDURE AutoRecCallback(theConn: ConnHandle; data: Ptr; refNum: LONGINT);
  340. BEGIN
  341.     { We can't call FTStart() or CMRemoveSearch() here as     }
  342.     { this proc might be called from Interrupt level        }
  343.     
  344.     IF (gFTSearchRefNum = refNum) THEN
  345.         gStartFT := TRUE;        { Set the flag to call FTStart in Idle    }
  346. END; { AutoRecCallBack    }
  347.  
  348.  
  349.  
  350. { ******************************************************************
  351. *    AddFTSearch        - Checks to see if the file transfer has an
  352. *                    auto-receive string, and adds a search to 
  353. *                    find it.
  354. *
  355. ********************************************************************* }
  356. {$S Main}
  357. PROCEDURE AddFTSearch;
  358. VAR
  359.     tempStr        : Str255;            { the string to look for    }
  360.     
  361. BEGIN    
  362.     IF (gFT <> NIL) AND (gConn <> NIL) THEN BEGIN
  363.         tempStr := gFT^^.AutoRec;        { Do I need to add a search        }
  364.         
  365.         IF (tempStr <> '') THEN BEGIN
  366.             gFTSearchRefNum := CMAddSearch(gConn,tempStr,cmSearchSevenBit,
  367.                                                             @AutoRecCallback);
  368.             IF gFTSearchRefNum = -1 THEN BEGIN
  369.                 AlertUser('Couldn''t add stream search',FALSE);
  370.                 gFTSearchRefNum := 0;
  371.             END;
  372.         END; { can autoreceive    }
  373.         
  374.     END; { good FT and Conn    }
  375.     
  376. END; { AddFTSearch        }
  377.  
  378.  
  379.  
  380. { ******************************************************************
  381. *    DoSend    - Initiates a File Transfer send from the menu command
  382. *
  383. ********************************************************************* }
  384. {$S Main}
  385. PROCEDURE DoSend;
  386. VAR
  387.     theReply    : SFReply;            { File Info                    }
  388.     where        : Point;            { Top Left of File dialog    }
  389.     numTypes    : INTEGER;            { File Types to display        }
  390.     typeList    : SFTypeList;
  391.     anyErr        : FTErr;            { Error handler                }
  392.     
  393. BEGIN
  394.     IF gFT <> NIL THEN BEGIN
  395.         SetPt(where, 100, 100);
  396.         
  397.         { If the FT tool can only send Text files, then            }
  398.         { only display text files, else display all types        }
  399.     
  400.         { Check to see if Text Only flag is set    }
  401.         IF BAND(gFT^^.attributes, ftTextOnly) <> 0 THEN BEGIN
  402.             typeList[0] := 'TEXT';
  403.             numTypes := 1;
  404.         END
  405.         ELSE
  406.             numTypes := -1;
  407.             
  408.         SFGetFile(where, 'File to Send', NIL, numTypes,
  409.                                         typeList, NIL, theReply);
  410.         
  411.         { Did the user hit OK or Cancel    }
  412.         IF theReply.good THEN BEGIN
  413.             { Transfer the file TO the remote    }
  414.             anyErr := FTStart(gFT,ftTransmitting,theReply);
  415.             
  416.             IF (anyErr <> noErr) THEN
  417.                 ;            { File Transfer tool will alert user on an error    }
  418.                 
  419.         END; { Good file    }
  420.     END; { Good FTHandle    }
  421.     
  422. END; { DoSend    }
  423.  
  424.  
  425. { ******************************************************************
  426. *    DoReceive    - Initiates a File Transfer receive from the menu
  427. *
  428. ********************************************************************* }
  429. {$S Main}
  430. PROCEDURE DoReceive;
  431. VAR
  432.     theReply        : SFReply;        { File Info            }
  433.     anyErr            : OSErr;        { Errors on Start    }
  434.     
  435. BEGIN
  436.     IF gFT <> NIL THEN BEGIN
  437.         
  438.         { Let the FT tool use its own default file info    }
  439.         theReply.vRefNum := 0;
  440.         theReply.fName := '';
  441.         
  442.         gStartFT := FALSE;        { Shut the flag down            }
  443.         
  444.         { We remove the search temporarily in case it comes        }
  445.         { across during the transfer. Will be re-added in the    }
  446.         { idle loop once the transfer is completed                }
  447.         
  448.         IF gConn <> NIL THEN
  449.             IF (gFT^^.autoRec <> '') AND (gFTSearchRefNum <> 0) THEN BEGIN
  450.                 CMRemoveSearch(gConn, gFTSearchRefNum);
  451.                 gFTSearchRefNum := 0;    { We found it already    }
  452.             END;
  453.         
  454.         { Start receiving the file                        }
  455.         { The rest gets transferred in the Idle loop    }
  456.         
  457.         anyErr := FTStart(gFT,ftReceiving,theReply);
  458.         
  459.         IF (anyErr <> noErr) THEN
  460.             ;            { File Transfer tool will alert user on an error    }
  461.             
  462.     END; { Good Handle    }
  463.     
  464. END; { DoReceive    }
  465.  
  466.  
  467. { ******************************************************************
  468. *    IsDAWindow    - Checks to see if a window belongs to a desk acc.
  469. *
  470. *        window        - the culprit
  471. *
  472. *        returns        - true if it's a DA
  473. *
  474. ********************************************************************* }
  475. {$S Main}
  476. FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
  477.  
  478. {Check if a window belongs to a desk accessory.}
  479.  
  480. BEGIN
  481.     IF window = NIL THEN
  482.         IsDAWindow := FALSE
  483.     ELSE    {DA windows have negative windowKinds}
  484.         IsDAWindow := WindowPeek(window)^.windowKind < 0;
  485. END; {IsDAWindow}
  486.  
  487.  
  488.  
  489. { ******************************************************************
  490. *    IsAppWindow    - Checks to see if a window belongs to our app
  491. *
  492. *        window        - the culprit
  493. *
  494. *        returns        - true if it's an app window
  495. *
  496. ********************************************************************* }
  497. {$S Main}
  498. FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
  499. VAR
  500.     theRefCon        : LONGINT;
  501.     
  502. BEGIN
  503.     { Check the userkind and the refcon for tool windows}
  504.     IF window = NIL THEN
  505.         IsAppWindow := FALSE
  506.     ELSE BEGIN
  507.         theRefCon := GetWRefCon(window);
  508.         WITH WindowPeek(window)^ DO
  509.             IsAppWindow := ((windowKind >= userKind) | (windowKind = dialogKind)) &
  510.                                 (gTerm <> TermHandle(theRefCon)) &
  511.                                 (gConn <> ConnHandle(theRefCon)) &
  512.                                 (gFT <> FTHandle(theRefCon));
  513.     END;
  514. END; {IsAppWindow}
  515.  
  516.  
  517.  
  518. { ******************************************************************
  519. *    AlertUser    - Informs the user of any errors
  520. *
  521. *        msg        - The string to display
  522. *        fatal    - Exit if this is a fatal error
  523. *
  524. ********************************************************************* }
  525. {$S Main}
  526. PROCEDURE AlertUser(msg: Str255; fatal: BOOLEAN); 
  527. VAR
  528.     itemHit    : INTEGER;
  529.     
  530. BEGIN
  531.     SetCursor(arrow);
  532.     
  533.     ParamText(msg,'','','');
  534.     itemHit := Alert(rUserAlert, NIL);
  535.     
  536.     IF fatal THEN
  537.         Terminate;
  538. END; { AlertUser    }
  539.  
  540.  
  541.  
  542. { ******************************************************************
  543. *    OpenConnection    - Initiates a connection
  544. *
  545. ********************************************************************* }
  546. {$S Main}
  547. PROCEDURE OpenConnection; 
  548. VAR
  549.     theErr    : CMErr;
  550.     sizes    : CMBufferSizes;        { Connection Tool data        }
  551.     status    : CMStatFlags;
  552.     
  553. BEGIN
  554.     IF (gConn <> NIL) THEN BEGIN
  555.     
  556.         { Get connection info        }
  557.         theErr := CMStatus(gConn, sizes, status);
  558.         
  559.         { If it isn't already open, then open it    }
  560.         IF (theErr = noErr) THEN
  561.             IF BAND(status, cmStatusOpen + cmStatusOpening) = 0 THEN
  562.                 theErr := CMOpen(gConn, FALSE, NIL, -1);
  563.         
  564.         IF (theErr <> noErr) THEN
  565.             ;            { Conn tool will alert user on an error        }
  566.     END;
  567. END; {OpenConnection}
  568.  
  569.  
  570.  
  571. { ******************************************************************
  572. *    CloseConnection    - Kills a connection
  573. *
  574. ********************************************************************* }
  575. {$S Main}
  576. PROCEDURE CloseConnection; 
  577. VAR
  578.     theErr    : CMErr;
  579.     sizes    : CMBufferSizes;        { Connection Tool data        }
  580.     status    : CMStatFlags;
  581.     
  582. BEGIN
  583.     { Kill the current connection    }
  584.     IF (gConn <> NIL) THEN BEGIN
  585.         theErr := CMStatus(gConn, sizes, status);
  586.         
  587.         { If it's open, then close it    }
  588.         IF (theErr = noErr) THEN
  589.             IF BAND(status, cmStatusOpen + cmStatusOpening) <> 0 THEN
  590.                 theErr := CMClose(gConn, FALSE, NIL, 0, TRUE);
  591.         
  592.         IF (theErr <> noErr) THEN
  593.             ;        { Conn tool will alert user on an error        }
  594.     END;
  595.     
  596. END; {CloseConnection}
  597.  
  598.  
  599.  
  600. { ******************************************************************
  601. *    DoCloseWindow    - Closes the window
  602. *
  603. *        window        - the culprit
  604. *
  605. *        returns        - always returns true
  606. *
  607. ********************************************************************* }
  608. {$S Main}
  609. FUNCTION DoCloseWindow(window: WindowPtr): BOOLEAN;
  610. BEGIN
  611.     DoCloseWindow := TRUE;
  612.     
  613.     IF IsDAWindow(window) THEN
  614.         CloseDeskAcc(WindowPeek(window)^.windowKind)
  615.     ELSE IF IsAppWindow(window) THEN BEGIN
  616.     
  617.         CloseConnection;            { Stop what we're doin'        }
  618.         
  619.         IF gTerm <> NIL THEN BEGIN    { Dispose of all the tools    }
  620.             HUnlock(Handle(gTerm));
  621.             TMDispose(gTerm);
  622.         END;
  623.         
  624.         IF gFT <> NIL THEN BEGIN
  625.             HUnlock(Handle(gFT));
  626.             FTDispose(gFT);
  627.         END;
  628.             
  629.         IF (gConn <> NIL) THEN BEGIN
  630.             HUnlock(Handle(gConn));
  631.             CMDispose(gConn);
  632.         END;
  633.                 
  634.         IF (gBuffer <> NIL) THEN    { Clean up our buffer        }
  635.             DisposPtr(gBuffer);
  636.             
  637.         DisposeWindow(window);
  638.     END; { App Window    }
  639.     
  640. END; {DoCloseWindow}
  641.  
  642.  
  643. { ******************************************************************
  644. *    FindToolID    - Tries to get the default tool proc id,
  645. *                otherwise, gets the first one it finds.
  646. *
  647. *        toolClass    - What kind of tool: term, ft, conn
  648. *
  649. *        returns        - the tool proc id or -1 if not found
  650. *
  651. ********************************************************************* }
  652. {$S Main}
  653. FUNCTION FindToolID(toolClass: OSType): INTEGER;
  654. VAR
  655.     toolName    : Str255;        { tool file name        }
  656.     anyErr        : OSErr;
  657.     procID        : INTEGER;        { tool fref number        }
  658.     
  659. BEGIN
  660.     procID := -1;                { Unknown tool            }
  661.     
  662.     IF (toolClass = ClassTM) THEN BEGIN
  663.         { If it can't get the default, get the 1st    }
  664.         toolName := kDefaultTermTool;
  665.         procID := TMGetProcID(toolName);
  666.         
  667.         IF (procID = -1) THEN BEGIN
  668.             anyErr := CRMGetIndToolName(toolClass,1,toolName);
  669.             IF (anyErr = noErr) THEN
  670.                 procID := TMGetProcID(toolName);
  671.         END;
  672.         
  673.     END { ClassTM}
  674.     
  675.     ELSE IF (toolClass = ClassCM) THEN BEGIN
  676.         { If it can't get the default, get the 1st    }
  677.         toolName := kDefaultConnTool;
  678.         procID := CMGetProcID(toolName);
  679.         
  680.         IF (procID = -1) THEN BEGIN
  681.             anyErr := CRMGetIndToolName(toolClass,1,toolName);
  682.             IF (anyErr = noErr) THEN
  683.                 procID := CMGetProcID(toolName);
  684.         END;
  685.         
  686.     END { ClassCM}
  687.         
  688.     ELSE IF (toolClass = ClassFT) THEN BEGIN
  689.         { If it can't get the default, get the 1st    }
  690.         toolName := kDefaultFTTool;
  691.         procID := FTGetProcID(toolName);
  692.         
  693.         IF (procID = -1) THEN BEGIN
  694.             anyErr := CRMGetIndToolName(toolClass,1,toolName);
  695.             IF (anyErr = noErr) THEN
  696.                 procID := FTGetProcID(toolName);
  697.         END;
  698.         
  699.     END; { ClassFT}
  700.     
  701.     FindToolID := procID;
  702.         
  703. END; {FindToolID}
  704.  
  705.  
  706. { ******************************************************************
  707. *    DoNewWindow    - Gets the window and creates the session
  708. *
  709. *        window        - the culprit
  710. *
  711. *        returns        - always returns true
  712. *
  713. ********************************************************************* }
  714. {$S Main}
  715. FUNCTION DoNewWindow: BOOLEAN;
  716. VAR
  717.     window        : WindowPtr;    { the window to create            }
  718.     theRect        : Rect;            { for the terminal bounds        }
  719.     procID        : INTEGER;        { tool's ref number                }
  720.     sizes        : CMBufferSizes;    { requested size of the buffers    }
  721.     
  722. BEGIN
  723.     { Get window                        }
  724.     window := GetNewWindow(rWindow, NIL, WindowPtr(-1));
  725.     SetPort(window);    
  726.     
  727.     { TERMINAL TOOL    }
  728.     procID := FindToolID(ClassTM);
  729.     IF (procID = -1) THEN
  730.         AlertUser('No terminal tools found',TRUE);
  731.         
  732.     theRect := window^.portRect;
  733.     
  734.     { No cache, breakproc, or clikloop    }
  735.     gTerm := TMNew(theRect,theRect,TMSaveBeforeClear,procID,window, 
  736.                         @TermSendProc,NIL,NIL,NIL,@ToolGetConnEnvirons,0,0);
  737.     IF gTerm = NIL THEN
  738.         AlertUser('Can''t create a terminal tool',TRUE);
  739.     
  740.     HLock(Handle(gTerm));
  741.     
  742.     { CONNECTION TOOL    }
  743.     procID := FindToolID(ClassCM);
  744.     IF (procID = -1) THEN
  745.         AlertUser('No connection tools found',TRUE);
  746.     
  747.     sizes[cmDataIn] := kBufferSize;        { Just the data channel please    }
  748.     sizes[cmDataOut] := kBufferSize;
  749.     sizes[cmCntlIn] := 0;
  750.     sizes[cmCntlOut] := 0;
  751.     sizes[cmAttnIn] := 0;
  752.     sizes[cmAttnOut] := 0;
  753.     
  754.     gConn := CMNew(procID, cmData, sizes, 0, 0);
  755.     IF gConn = NIL THEN
  756.         AlertUser('Can''t create a connection tool',TRUE);
  757.         
  758.     HLock(Handle(gConn));
  759.     
  760.     { Allocate space for the read/writes using the number    }
  761.     { returned by the connection tool                        }
  762.     
  763.     gBuffer := NewPtr(sizes[cmDataIn]);
  764.     IF MemError <> noErr THEN
  765.         AlertUser('Out of memory, eh',TRUE);
  766.     
  767.     { FILE TRANSFER TOOL    }
  768.     procID := FindToolID(ClassFT);
  769.     IF (procID = -1) THEN
  770.         AlertUser('No file transfer tools found',FALSE);
  771.     
  772.     { No read/write proc.  Let the tool use its own        }
  773.     gFT := FTNew(procID,0,@FTsendProc,@FTreceiveProc,NIL,NIL,
  774.                                     @ToolGetConnEnvirons,window,0,0);
  775.     IF gFT = NIL THEN
  776.         AlertUser('Can''t create a file transfer tool',TRUE);
  777.         
  778.     HLock(Handle(gFT));
  779.     
  780.     gWasFT := FALSE;            { FT in progress                    }
  781.     gStartFT := FALSE;            { Auto-received string found        }
  782.     gFTSearchRefNum := 0;        { Clear the search refnum            }
  783.                 
  784.     AddFTSearch;                { Look for the auto-receive string    }
  785.     
  786.     DoNewWindow := TRUE;
  787.                         
  788. END; {DoNewWindow}
  789.  
  790.  
  791.  
  792. { ******************************************************************
  793. *    Initialize        - Inits the various toolbox stuff
  794. *
  795. ********************************************************************* }
  796.  
  797. {$S Initialize}
  798. PROCEDURE Initialize;
  799.  
  800. VAR
  801.     menuBar            : Handle;
  802.     window            : WindowPtr;
  803.     ignoreError        : OSErr;
  804.     total, contig    : LongInt;
  805.     ignoreResult    : BOOLEAN;
  806.     event            : EventRecord;
  807.     count            : INTEGER;
  808.     TerraMac        : SysEnvRec;    {set up by Initialize}
  809.     err                : INTEGER;
  810.  
  811. BEGIN
  812.     { Do we have Multifinder?    }
  813.     gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
  814.     gInBackground := FALSE;
  815.  
  816.     { Standard Fare        }
  817.     InitGraf(@thePort);
  818.     InitFonts;
  819.     InitWindows;
  820.     InitMenus;
  821.     TEInit;
  822.     InitDialogs(NIL);
  823.     InitCursor;
  824.     
  825.     { Bring us to the front        }
  826.     FOR count := 1 TO 3 DO
  827.         ignoreResult := GetNextEvent(everyEvent, event);
  828.     
  829.     { Does CommToolbox Exist    }
  830.     IF NOT TrapAvailable(_CommToolboxTrap, OSTrap) THEN
  831.         AlertUser('ACK!! No CommToolbox',TRUE);
  832.     
  833.     { Check for System 6.0 or better, 64K ROM    }
  834.     ignoreError := SysEnvirons(kSysEnvironsVersion, TerraMac);
  835.     
  836.     WITH TerraMac DO
  837.         IF (systemVersion < $0600) OR (machineType < 0) THEN 
  838.             AlertUser('Need System 6.0 or better',TRUE);
  839.      
  840.     { Check various memory configs                }
  841.     IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN 
  842.         AlertUser('Out of Memory, eh',TRUE);
  843.     
  844.     PurgeSpace(total, contig);
  845.     IF total < kMinSpace THEN 
  846.         AlertUser('Out of Memory, eh',TRUE);
  847.     
  848.     { Load up the Communications Toolbox        }
  849.     { Must Initialize CRM & CTBUtilities first    }
  850.     err :=     InitCTBUtilities;
  851.     err :=     InitCRM;
  852.  
  853.     err := InitTM;
  854.     IF err = TMNoTools THEN
  855.         AlertUser('No terminal tools found',TRUE);
  856.     
  857.     err :=     InitCM;    { initializes the Connection Manager }
  858.     IF err = CMNoTools THEN
  859.         AlertUser('No connection tools found',TRUE);
  860.     
  861.     err :=     InitFT;    { initializes the File Transfer Manager }
  862.     IF err = FTNoTools THEN
  863.         AlertUser('No file transfer tools found',FALSE);
  864.         
  865.     gTerm := NIL;
  866.     gConn := NIL;
  867.     gFT := NIL;
  868.     gFTSearchRefNum := 0;
  869.  
  870.     IF NOT DoNewWindow THEN
  871.         AlertUser('Can''t create a session',TRUE);
  872.  
  873.     menuBar := GetNewMBar(rMenuBar);        {read menus into menu bar}
  874.     IF menuBar = NIL THEN 
  875.         AlertUser('Can''t get the menu bar',TRUE);
  876.     SetMenuBar(menuBar);                    {install menus}
  877.     DisposHandle(menuBar);
  878.     
  879.     AddResMenu(GetMHandle(mApple), 'DRVR');    {add DA names to Apple menu}
  880.     DrawMenuBar;
  881.  
  882.     gStopped := TRUE;
  883. END; {Initialize}
  884.  
  885.  
  886. { ******************************************************************
  887. *    Terminate        - Cleans up and exits
  888. *
  889. ********************************************************************* }
  890.  
  891. {$S Main}
  892. PROCEDURE Terminate;
  893. VAR
  894.     aWindow    : WindowPtr;        { the window to shut        }
  895.     closed    : BOOLEAN;            { Are we done, yet            }
  896.  
  897. BEGIN
  898.     { Close all the open windows    }
  899.     closed := TRUE;
  900.  
  901.     aWindow := FrontWindow;    
  902.     
  903.     REPEAT        
  904.         IF (aWindow <> NIL) THEN
  905.             IF IsAppWindow(aWindow) THEN
  906.                 closed := DoCloseWindow(aWindow);
  907.                 
  908.         { Try the next window    }
  909.         IF (aWindow <> NIL) THEN
  910.             aWindow := WindowPtr(WindowPeek(aWindow)^.nextWindow); 
  911.         
  912.     UNTIL (NOT closed) | (aWindow = NIL);
  913.     
  914.     IF closed THEN
  915.         ExitToShell;                            {exit if no cancellation}
  916. END; {Terminate}
  917.  
  918.  
  919.  
  920. { ******************************************************************
  921. *    AdjustMenus        - Enables & Disables items based on current state
  922. *
  923. ********************************************************************* }
  924.  
  925. {$S Main}
  926. PROCEDURE AdjustMenus;
  927. VAR
  928.     window            : WindowPtr;        { whose in front            }
  929.     menu            : MenuHandle;        { the menu to manipulate    }
  930.     theErr            : CMErr;
  931.     sizes            : CMBufferSizes;        { Connection tool data        }
  932.     status            : CMStatFlags;
  933.  
  934. BEGIN
  935.     window := FrontWindow;
  936.  
  937.     menu := GetMHandle(mFile);
  938.     IF (menu = NIL) THEN
  939.         AlertUser('Can''t get menu resource', TRUE);
  940.         
  941.     IF (gConn <> NIL) THEN BEGIN
  942.         theErr := CMStatus(gConn,sizes,status);
  943.         IF (theErr = noErr) THEN BEGIN
  944.             IF NOT IsDAWindow(window) THEN BEGIN
  945.                 SetItem(menu,iOpen,'Open Connection');
  946.                 SetItem(menu,iClose,'Close Connection');
  947.                 
  948.                 { Let the menu show the proper state of the union    }
  949.                 IF BAND(status, cmStatusOpen + cmStatusOpening) = 0 THEN BEGIN
  950.                     EnableItem(menu, iOpen);
  951.                     DisableItem(menu, iClose);
  952.                 END
  953.                 ELSE BEGIN
  954.                     DisableItem(menu, iOpen);
  955.                     EnableItem(menu, iClose);
  956.                 END;
  957.                 
  958.                 { Check state of the FT tool to Enable send/receive    }
  959.                 DisableItem(menu,iSendFile);
  960.                 DisableItem(menu,iReceiveFile);
  961.                 
  962.                 IF (gFT <> NIL) THEN BEGIN
  963.                     IF BAND(gFT^^.attributes,ftSendDisable) = 0 THEN
  964.                         EnableItem(menu,iSendFile);
  965.                         
  966.                     IF BAND(gFT^^.attributes,ftReceiveDisable) = 0 THEN
  967.                         EnableItem(menu,iReceiveFile);                    
  968.                 END;
  969.             END
  970.             ELSE BEGIN
  971.                 { Set for desk accesories    }
  972.                 SetItem(menu,iOpen,'Open');
  973.                 SetItem(menu,iClose,'Close');
  974.                 DisableItem(menu, iOpen);
  975.                 EnableItem(menu,iClose);
  976.                 DisableItem(menu,iSendFile);
  977.                 DisableItem(menu,iReceiveFile);
  978.             END;
  979.             
  980.         END; { good status    }
  981.     END; { good connection    }
  982.     
  983.     
  984.     menu := GetMHandle(mEdit);
  985.     IF (menu = NIL) THEN
  986.         AlertUser('Can''t get menu resource', TRUE);
  987.     
  988.     IF IsDAWindow(window) THEN BEGIN        { DAs might use this menu    }
  989.         EnableItem(menu, iUndo);
  990.         EnableItem(menu, iCut);
  991.         EnableItem(menu, iCopy);
  992.         EnableItem(menu, iPaste);
  993.         EnableItem(menu, iClear);
  994.     END ELSE BEGIN                            { but we don't use it yet    }
  995.         DisableItem(menu, iUndo);
  996.         DisableItem(menu, iCut);
  997.         DisableItem(menu, iCopy);
  998.         DisableItem(menu, iClear);
  999.         DisableItem(menu, iPaste);
  1000.     END;
  1001.  
  1002.     menu := GetMHandle(mSettings);
  1003.     IF (menu = NIL) THEN
  1004.         AlertUser('Can''t get menu resource', TRUE);
  1005.         
  1006.     IF NOT IsDAWindow(window) THEN BEGIN        { Enable if we're front    }
  1007.         EnableItem(menu, iConnection);
  1008.         EnableItem(menu, iFileTransfer);
  1009.         EnableItem(menu, iTerminal);
  1010.     END ELSE BEGIN
  1011.         DisableItem(menu, iConnection);
  1012.         DisableItem(menu, iFileTransfer);
  1013.         DisableItem(menu, iTerminal);
  1014.     END;
  1015.     
  1016. END; {AdjustMenus}
  1017.  
  1018.  
  1019. { ******************************************************************
  1020. *    DoToolMenu        - Tries to give the menu to the tool
  1021. *
  1022. *        menuID        - the menu info from DoMenuCommand
  1023. *        menuItem
  1024. *
  1025. *        returns        - TRUE if a tool handled the menu
  1026. *
  1027. ********************************************************************* }
  1028. {$S Main}
  1029. FUNCTION DoToolMenu(menuID, menuItem: INTEGER): BOOLEAN;
  1030. BEGIN
  1031.     DoToolMenu := FALSE;
  1032.     
  1033.     IF gTerm <> NIL THEN
  1034.         IF TMMenu(gTerm, menuID, menuItem) THEN BEGIN
  1035.             DoToolMenu := TRUE;
  1036.             Exit(DoToolMenu);
  1037.         END;
  1038.  
  1039.     IF gConn <> NIL THEN
  1040.         IF CMMenu(gConn, menuID, menuItem) THEN BEGIN
  1041.             DoToolMenu := TRUE;
  1042.             Exit(DoToolMenu);
  1043.         END;
  1044.     
  1045.     IF gFT <> NIL THEN
  1046.         IF FTMenu(gFT, menuID, menuItem) THEN
  1047.             DoToolMenu := TRUE;
  1048.             
  1049. END; {DoToolMenu}
  1050.  
  1051.  
  1052.  
  1053. { ******************************************************************
  1054. *    DoMenuCommand    - Executes a menu command
  1055. *
  1056. *        menuResult    - the menu id and item number
  1057. *
  1058. ********************************************************************* }
  1059.  
  1060. {$S Main}
  1061. PROCEDURE DoMenuCommand(menuResult: LONGINT);
  1062. VAR
  1063.     menuID            : INTEGER;        { resource ID of the selected menu    }
  1064.     menuItem        : INTEGER;        { item number of the selected menu    }
  1065.     itemHit            : INTEGER;        { for the alert                        }
  1066.     daName            : Str255;        { for opening desk accesories        }
  1067.     daRefNum        : INTEGER;
  1068.     handledByDA        : BOOLEAN;        { DA edit menu handling                }
  1069.     ignore            : BOOLEAN;        
  1070.     where            : Point;        { For choose dialog                    }
  1071.     result            : INTEGER;
  1072.  
  1073. BEGIN
  1074.     menuID := HiWrd(menuResult);    {use built-ins (for efficiency)...}
  1075.     menuItem := LoWrd(menuResult);    {to get menu item number and menu number}
  1076.     
  1077.     { First see if the menu belonged to a tool    }
  1078.         
  1079.     IF NOT DoToolMenu(menuID,menuItem) THEN
  1080.         CASE menuID OF
  1081.             mApple:
  1082.                 CASE menuItem OF
  1083.                     iAbout:                {bring up alert for About}
  1084.                         itemHit := Alert(rAboutAlert, NIL);
  1085.                     OTHERWISE BEGIN        {all non-About items in this menu are DAs}
  1086.                         GetItem(GetMHandle(mApple), menuItem, daName);
  1087.                         daRefNum := OpenDeskAcc(daName);
  1088.                     END;
  1089.                 END; { case    }
  1090.                 
  1091.             mFile:
  1092.                 CASE menuItem OF
  1093.                     iOpen:
  1094.                         IF NOT IsDAWindow(FrontWindow) THEN
  1095.                             OpenConnection;
  1096.                         
  1097.                     iClose:
  1098.                         IF IsDAWindow(FrontWindow) THEN
  1099.                             ignore := DoCloseWindow(FrontWindow)
  1100.                         ELSE
  1101.                             CloseConnection;
  1102.                             
  1103.                     iSendFile:
  1104.                         IF NOT IsDAWindow(FrontWindow) THEN
  1105.                             DoSend;
  1106.                         
  1107.                     iReceiveFile:
  1108.                         IF NOT IsDAWindow(FrontWindow) THEN
  1109.                             DoReceive;
  1110.                             
  1111.                     iQuit:
  1112.                         Terminate;
  1113.                 END; { case    }
  1114.                 
  1115.             mEdit:                        {call SystemEdit for DA editing & MultiFinder}
  1116.                 handledByDA := SystemEdit(menuItem-1);    {since we don't do any editing}
  1117.                 
  1118.             mSettings:
  1119.                 CASE menuItem OF
  1120.                     iConnection:
  1121.                         IF gConn <> NIL THEN BEGIN
  1122.                             HUnlock(Handle(gConn));
  1123.                             
  1124.                             SetPt(where,10,40);
  1125.                             result := CMChoose(gConn, where, NIL);
  1126.                             
  1127.                             CASE result OF
  1128.                                 chooseDisaster,
  1129.                                 chooseFailed:
  1130.                                     AlertUser('Connection choose failed',(result = chooseDisaster));
  1131.                                 chooseOKMajor:
  1132.                                     AddFTSearch;
  1133.                             END;
  1134.                             
  1135.                             HLock(Handle(gConn));
  1136.                         END; { good conn    }
  1137.                         
  1138.                     iFileTransfer:
  1139.                         IF (gFT <> NIL) THEN BEGIN
  1140.                             HUnlock(Handle(gFT));
  1141.                             
  1142.                             SetPt(where,10,40);
  1143.                             result := FTChoose(gFT, where, NIL);
  1144.                             
  1145.                             CASE result OF
  1146.                                 chooseDisaster,
  1147.                                 chooseFailed:
  1148.                                     AlertUser('File Transfer choose failed',
  1149.                                                             (result = chooseDisaster));
  1150.                                 chooseOKMinor,
  1151.                                 chooseOKMajor: BEGIN
  1152.                                     { Get rid of the old search            }
  1153.                                     IF (gFTSearchRefNum <> 0) AND (gConn <> NIL) THEN
  1154.                                         CMRemoveSearch(gConn,gFTSearchRefNum);
  1155.                                     gFTSearchRefNum := 0;
  1156.                                     
  1157.                                     AddFTSearch;    { Add the new FT tool search    }
  1158.                                 END;
  1159.                             END;
  1160.                             
  1161.                             HLock(Handle(gFT));
  1162.                         END; { good ft    }
  1163.                         
  1164.                     iTerminal: 
  1165.                         IF (gTerm <> NIL) THEN BEGIN
  1166.                             HLock(Handle(gTerm));
  1167.                             
  1168.                             SetPt(where,10,40);
  1169.                             result := TMChoose(gTerm, where, NIL);
  1170.                             
  1171.                             IF (result < 0) THEN
  1172.                                 AlertUser('Terminal choose failed',(result = chooseDisaster));
  1173.                             
  1174.                             HUnlock(Handle(gTerm));
  1175.                         END; { good term    }
  1176.                         
  1177.                 END; { case    menuitem    }
  1178.                     
  1179.         END; { case menuid    }
  1180.     
  1181.     HiliteMenu(0);                    {unhighlight what MenuSelect (or MenuKey) hilited}
  1182. END; {DoMenuCommand}
  1183.  
  1184.  
  1185. { ******************************************************************
  1186. *    DoUpdate    - Updates the window
  1187. *
  1188. *        window    - target of teh update
  1189. *
  1190. ********************************************************************* }
  1191. {$S Main}
  1192. PROCEDURE DoUpdate(window: WindowPtr);
  1193. VAR
  1194.     savedClip    : RgnHandle;        { saved info for reset later    }
  1195.     savedPort    : GrafPtr;
  1196.     
  1197. BEGIN
  1198.     IF IsAppWindow(window) THEN BEGIN
  1199.         GetPort(savedPort);
  1200.         SetPort(window);
  1201.         
  1202.         { Clip to the window content    }
  1203.         savedClip := NewRgn;
  1204.         GetClip(savedClip);
  1205.         ClipRect(window^.portRect);
  1206.         
  1207.         BeginUpdate(window);
  1208.             IF gTerm <> NIL THEN    { Update the terminal tool        }
  1209.                 TMUpdate(gTerm, window^.visRgn);
  1210.         EndUpdate(window);
  1211.         
  1212.         SetClip(savedClip);
  1213.         DisposeRgn(savedClip);
  1214.         
  1215.         SetPort(savedPort);
  1216.     END;
  1217. END; {DoUpdate}
  1218.  
  1219.  
  1220. { ******************************************************************
  1221. *    DoResume    - Suspends/Resumes the window
  1222. *
  1223. *        becomingActive    - Resume or Suspend
  1224. *
  1225. ********************************************************************* }
  1226.  
  1227. {$S Main}
  1228. PROCEDURE DoResume(becomingActive: BOOLEAN);
  1229. VAR
  1230.     theWindow    : WindowPtr;
  1231.     savedPort    : GrafPtr;
  1232.     
  1233. BEGIN
  1234.     { Since the front window could be a tool window, we need    }
  1235.     { to find the app window by walking the list so we can        }
  1236.     { send resume messages to the tools                            }
  1237.     
  1238.     GetPort(savedPort);
  1239.     
  1240.     theWindow := FrontWindow;
  1241.     
  1242.     WHILE (theWindow <> NIL) DO BEGIN
  1243.         IF IsAppWindow(theWindow) THEN BEGIN
  1244.             SetPort(theWindow);
  1245.         
  1246.             { Tools need to adjust their menus, text selection, etc    }            
  1247.             IF gTerm <> NIL THEN
  1248.                 TMResume(gTerm, becomingActive);
  1249.             
  1250.             IF gConn <> NIL THEN
  1251.                 CMResume(gConn, becomingActive);
  1252.         
  1253.             IF gFT <> NIL THEN
  1254.                 FTResume(gFT, becomingActive);
  1255.         END; { app window    }
  1256.         
  1257.         { Try the next window    }
  1258.         theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1259.     END;
  1260.     
  1261.     SetPort(savedPort);
  1262.     
  1263. END; {DoResume}
  1264.  
  1265.  
  1266. { ******************************************************************
  1267. *    DoActivate    - (De)Activates the window
  1268. *
  1269. *        window            - target of the update
  1270. *        becomingActive    - Activate or Deactivate
  1271. *
  1272. ********************************************************************* }
  1273.  
  1274. {$S Main}
  1275. PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN);
  1276. BEGIN
  1277.     IF IsAppWindow(window) THEN BEGIN
  1278.         SetPort(window);
  1279.     
  1280.         { Tools need to adjust their menus, text selection, etc    }            
  1281.         IF gTerm <> NIL THEN
  1282.             TMActivate(gTerm, becomingActive);
  1283.         
  1284.         IF gConn <> NIL THEN
  1285.             CMActivate(gConn, becomingActive);
  1286.     
  1287.         IF gFT <> NIL THEN
  1288.             FTActivate(gFT, becomingActive);
  1289.     END;
  1290.     
  1291. END; {DoActivate}
  1292.  
  1293.  
  1294. { ******************************************************************
  1295. *    AdjustCursor    - Updates mouse cursor depending on location
  1296. *
  1297. *        mouse        - the location of the mouse (global coords)
  1298. *
  1299. ********************************************************************* }
  1300. {$S Main}
  1301. PROCEDURE AdjustCursor(mouse: Point);
  1302. VAR
  1303.     window                : WindowPtr;
  1304.  
  1305. BEGIN
  1306.     window := FrontWindow;        { Adjust only if front            }
  1307.     
  1308.     IF (NOT gInBackground) AND (IsAppWindow(window)) THEN BEGIN
  1309.         GlobalToLocal(mouse);
  1310.         
  1311.         { If it's outside the content, set to arrow        }
  1312.         { otherwise the terminal tool will  handle it    }
  1313.         
  1314.         IF (gTerm <> NIL) THEN
  1315.             IF NOT PtInRect(mouse,gTerm^^.viewRect) THEN
  1316.                 InitCursor;
  1317.                 
  1318.     END; { app window    }
  1319.     
  1320. END; {AdjustCursor}
  1321.  
  1322.  
  1323. { ******************************************************************
  1324. *    DoToolEvent        - Tries to pass the event to a tool if the 
  1325. *                    window is a tool window
  1326. *
  1327. *        event        - the event received
  1328. *
  1329. *        returns        - True if the tool handled it
  1330. *
  1331. ********************************************************************* }
  1332. {$S Main}
  1333. FUNCTION DoToolEvent(event: EventRecord; window: WindowPtr): BOOLEAN;
  1334. BEGIN
  1335.     IF (window <> NIL) THEN BEGIN
  1336.         DoToolEvent := TRUE;
  1337.         
  1338.         IF (gFT <> NIL) AND 
  1339.                 (gFT = FTHandle(GetWRefCon(window))) THEN
  1340.             FTEvent(gFT, event)
  1341.         ELSE IF (gConn <> NIL) AND 
  1342.                 (gConn = ConnHandle(GetWRefCon(window))) THEN
  1343.             CMEvent(gConn, event)
  1344.         ELSE IF (gTerm <> NIL) AND 
  1345.                 (gTerm = TermHandle(GetWRefCon(window))) THEN
  1346.             TMEvent(gTerm, event)
  1347.         ELSE
  1348.             DoToolEvent := FALSE;
  1349.     END
  1350.     ELSE
  1351.         DoToolEvent := FALSE;
  1352.         
  1353. END; {DoToolEvent}
  1354.  
  1355.  
  1356.  
  1357. { ******************************************************************
  1358. *    DoEvent    - Updates mouse cursor depending on location
  1359. *
  1360. *        event    - the event to handle
  1361. *
  1362. ********************************************************************* }
  1363. {$S Main}
  1364. PROCEDURE DoEvent(event: EventRecord);
  1365. VAR
  1366.     part,                            { where the mouse click was    }
  1367.     err            : INTEGER;
  1368.     window        : WindowPtr;        { the click's window        }
  1369.     key            : CHAR;                { the letter typed            }
  1370.     aPoint        : Point;            { for the dialog top left    }
  1371.     result        : LONGINT;            { result from MenuKey        }
  1372.     processed    : BOOLEAN;            { Did the App handle it        }
  1373.  
  1374. BEGIN
  1375.     CASE event.what OF
  1376.         mouseDown: BEGIN
  1377.             part := FindWindow(event.where, window);
  1378.  
  1379.             CASE part OF
  1380.                 inMenuBar: BEGIN            {process the menu command}
  1381.                     AdjustMenus;
  1382.                     DoMenuCommand(MenuSelect(event.where));
  1383.                 END;
  1384.                 
  1385.                 inSysWindow:                {let the system handle the mouseDown}
  1386.                     SystemClick(event, window);
  1387.                     
  1388.                 inContent:
  1389.                     { The terminal tool needs to handle selections    }
  1390.                     IF NOT DoToolEvent(event,window) THEN BEGIN
  1391.                         IF window <> FrontWindow THEN
  1392.                             SelectWindow(window)
  1393.                         ELSE IF (gTerm <> NIL) THEN
  1394.                             TMClick(gTerm, event);
  1395.                     END;
  1396.                         
  1397.                 inDrag:        {pass screenBits.bounds to get all gDevices}
  1398.                     IF NOT DoToolEvent(event,window) THEN
  1399.                         DragWindow(window, event.where, screenBits.bounds);
  1400.                     
  1401.                 inGrow,
  1402.                 inZoomIn, inZoomOut,
  1403.                 inGoAway:
  1404.                     IF DoToolEvent(event,window) THEN ;
  1405.             END; { Case Mousedown    }
  1406.                 
  1407.         END; { Mousedown    }
  1408.         
  1409.         keyDown, autoKey: BEGIN                {check for menukey equivalents}
  1410.             window := FrontWindow;
  1411.             
  1412.             { Get the key    }
  1413.             key := CHR(BAnd(event.message, charCodeMask));
  1414.             processed := FALSE;
  1415.             
  1416.             { The terminal tool might be mapping the cmd key     }
  1417.             { so if menukey fails, send it to the tool            }
  1418.             
  1419.             IF BAND(event.modifiers, cmdKey) <> 0 THEN BEGIN
  1420.                 AdjustMenus;            {enable/disable/check menu items properly}
  1421.                 result := MenuKey(key);
  1422.                 IF result <> 0 THEN BEGIN
  1423.                     processed := TRUE;
  1424.                     DoMenuCommand(result)
  1425.                 END;
  1426.             END;
  1427.             
  1428.             IF (gTerm <> NIL) AND NOT processed THEN
  1429.                 IF NOT DoToolEvent(event,window) THEN
  1430.                     TMKey(gTerm, event);            
  1431.         END;
  1432.         
  1433.         activateEvt: BEGIN
  1434.             window := WindowPtr(event.message);
  1435.             
  1436.             IF NOT DoToolEvent(event,window) THEN
  1437.                 DoActivate(window, BAND(event.modifiers, activeFlag) <> 0);
  1438.         END;
  1439.         
  1440.         updateEvt: BEGIN
  1441.             window := WindowPtr(event.message);
  1442.             
  1443.             IF NOT DoToolEvent(event,window) THEN
  1444.                 DoUpdate(window);
  1445.         END;
  1446.         
  1447.         diskEvt:
  1448.             IF HiWrd(event.message) <> noErr THEN BEGIN
  1449.                 SetPt(aPoint, kDILeft, kDITop);
  1450.                 err := DIBadMount(aPoint, event.message);
  1451.             END;
  1452.             
  1453.         kOSEvent:
  1454.             { Send to frontmost tool window AND all tools    }
  1455.             { as this is an application-wide event            }
  1456.             
  1457.             CASE BAnd(BRotL(event.message, 8),$FF) OF    {high byte of message}
  1458.                 kSuspendResumeMessage: BEGIN
  1459.                     IF NOT DoToolEvent(event,FrontWindow) THEN
  1460.                         ;
  1461.                         
  1462.                     gInBackground := BAnd(event.message, kResumeMask) = 0;
  1463.                     DoResume(NOT gInBackground);
  1464.                 END;
  1465.             END;
  1466.     END;
  1467. END; {DoEvent}
  1468.  
  1469.  
  1470. { ******************************************************************
  1471. *    DoIdle    - Idles all the tools
  1472. *
  1473. ********************************************************************* }
  1474. {$S Main}
  1475. PROCEDURE DoIdle;
  1476. VAR
  1477.     theWindow     : WindowPtr;                { The target to idle        }
  1478.     doFT         : BOOLEAN;                    { route data to FT Tool        }
  1479.     doTM         : BOOLEAN;                    { route data to Term Tool    }
  1480.     savedPort    : GrafPtr;                    { for later reset            }
  1481.     
  1482. BEGIN
  1483.     GetPort(savedPort);                        { Save for later            }
  1484.     theWindow := FrontWindow;                { Gimme the first one        }
  1485.     
  1486.     { Give idle time for the window    }
  1487.     WHILE (theWindow <> NIL) DO BEGIN
  1488.         IF IsAppWindow(theWindow) THEN BEGIN
  1489.             SetPort(theWindow);                    { Focus on it                }
  1490.             
  1491.             IF gConn <> NIL THEN            { Give time to the connection    }
  1492.                 CMIdle(gConn);
  1493.                 
  1494.             doFT := FALSE;                    { Send data to FT tool            }
  1495.             doTM := TRUE;                    { Send data to terminal tool    }
  1496.             
  1497.             IF gFT <> NIL THEN BEGIN
  1498.                 { Is there a file transfer in progress ??    }
  1499.                 IF BAND(gFT^^.flags, ftIsFTMode) <> 0 THEN BEGIN
  1500.                     doFT := TRUE;
  1501.                     gWasFT := TRUE;
  1502.                     
  1503.                     { If the FT tool uses my connection then    }
  1504.                     { don't route data to the terminal tool        }
  1505.                     
  1506.                     IF BAND(gFT^^.attributes, ftSameCircuit) <> 0 THEN 
  1507.                         doTM := FALSE;
  1508.                 END    { In progress    }
  1509.                 
  1510.                 ELSE BEGIN
  1511.                     IF gWasFT THEN BEGIN
  1512.                         { FT no longer in progress        }
  1513.                         gWasFT := FALSE;
  1514.                         
  1515.                         { FT tool will alert the user    }
  1516.                         IF BAND(gFT^^.flags, FTSucc) = 0 THEN
  1517.                             ;
  1518.                         
  1519.                         { The old search was removed for the transfer    }
  1520.                         { so we need to re-add it here                    }
  1521.                         AddFTSearch;
  1522.                     END;
  1523.                                         
  1524.                     { AutoReceive string was received ?    }
  1525.                     IF gStartFT THEN
  1526.                         DoReceive;
  1527.                 END; { No FT in progress    }
  1528.                 
  1529.                 IF doFT THEN            { Give time to FT tool                }
  1530.                     FTExec(gFT);
  1531.                 
  1532.             END; { Good FT Handle    }
  1533.                                 
  1534.             IF gTerm <> NIL THEN BEGIN
  1535.                 { Send data to terminal    }
  1536.                 IF doTM THEN BEGIN
  1537.                     TMIdle(gTerm);                { So it can blink its cursor, etc    }
  1538.                     
  1539.                     TermRecvProc;                { Send Data to the terminal            }
  1540.                 END; { Send data to terminal    }
  1541.                 
  1542.             END; { Good Terminal    }
  1543.             
  1544.         END; { App Window    }
  1545.         
  1546.         { Try the next window    }
  1547.         theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1548.             
  1549.     END; { while each window    }
  1550.             
  1551.     SetPort(savedPort);                        { Back to the way it was        }
  1552.         
  1553. END; { DoIdle    }
  1554.  
  1555.  
  1556. { ******************************************************************
  1557. *    EventLoop    - The main event loop 
  1558. *
  1559. ********************************************************************* }
  1560. {$S Main}
  1561. PROCEDURE EventLoop;
  1562. VAR
  1563.     gotEvent    : BOOLEAN;
  1564.     event        : EventRecord;
  1565.  
  1566. BEGIN
  1567.     REPEAT
  1568.         DoIdle;
  1569.         
  1570.         IF gHasWaitNextEvent THEN     { put us 'asleep' forever under MultiFinder    }
  1571.             gotEvent := WaitNextEvent(everyEvent, event, 0, NIL)
  1572.         ELSE BEGIN
  1573.             SystemTask;                { must be called if using GetNextEvent        }
  1574.             gotEvent := GetNextEvent(everyEvent, event);
  1575.         END;
  1576.         
  1577.         IF gotEvent THEN BEGIN
  1578.             AdjustCursor(event.where);             {make sure we have the right cursor}
  1579.             DoEvent(event);
  1580.         END;
  1581.         
  1582.         AdjustCursor(event.where);
  1583.     UNTIL FALSE;                    {loop forever; we quit through an ExitToShell}
  1584. END; {EventLoop}
  1585.  
  1586.  
  1587. PROCEDURE _DataInit; EXTERNAL;
  1588.  
  1589.  
  1590. {$S Main}
  1591. BEGIN
  1592.     UnloadSeg(@_DataInit);    { note that _DataInit must not be in Main!            }
  1593.          
  1594.     MaxApplZone;            { expand the heap so code segments load at the top    }
  1595.  
  1596.     Initialize;                { initialize the program                            }
  1597.     UnloadSeg(@Initialize);    { note that Initialize must not be in Main!            }
  1598.  
  1599.     EventLoop;                { call the main event loop                            }
  1600. END.
  1601.